#include "Libraries/GameKitFL.h"
#include "Blueprint/UserWidget.h"
#include "Animation/WidgetAnimation.h"
#include "Framework/SlotBasedSaveGame.h"
#include "Data/BaseData.h"
#include "Data/GameInstanceInterface.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/PlayerController.h"
#include "Blueprint/WidgetBlueprintLibrary.h"
#include "Data/PlayerControllerInterface.h"
#include "Libraries/MissionSystemFL.h"
#include "Component/MissionComponent.h"
#include "Engine/World.h"
// #include "Libraries/CommonLibrary.h"

EGameState UGameKitFL::GetCurrentGameState()
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		return GameInstanceInterfacePtr->PassGameState();
	}
	return EGameState::BeginPlay;
}

bool UGameKitFL::GameStateTransition(EGameState DesiredGameState)
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		return GameInstanceInterfacePtr->UpdateGameState(DesiredGameState);
	}
	else return false;
}

void UGameKitFL::SwitchInputMode(UUserWidget* WidgetToFocus, const EMouseLockMode& MouseLockMode, const EInputMode& InputMode)
{
	APlayerController* PlayerController = Cast<APlayerController>(UGameplayStatics::GetPlayerController(GWorld, 0));
	if (!PlayerController->IsValidLowLevel()) return;
	switch (InputMode)
	{
	case EInputMode::GameOnly:
		UWidgetBlueprintLibrary::SetInputMode_GameAndUIEx(PlayerController);
		PlayerController->bShowMouseCursor = false;
		break;
	case EInputMode::UIOnly:
		UWidgetBlueprintLibrary::SetInputMode_UIOnlyEx(PlayerController, WidgetToFocus, MouseLockMode);
		PlayerController->bShowMouseCursor = true;
		break;
	case EInputMode::GameAndUI:
		UWidgetBlueprintLibrary::SetInputMode_GameAndUIEx(PlayerController, WidgetToFocus, MouseLockMode);
		PlayerController->bShowMouseCursor = true;
		break;
	default:
		break;
	}
}

float UGameKitFL::CalculateAnimationCurrentTime(UUserWidget* SelfReference, const UWidgetAnimation* InAnimation)
{
	if (!SelfReference->IsPlayingAnimation()) return 0.f;
	float CurrentPlayTime = SelfReference->PauseAnimation(InAnimation);
	if (CurrentPlayTime == 0.f) {
		return 0.f;
	}
	else {
		return InAnimation->GetEndTime() - CurrentPlayTime;
	}
}

void UGameKitFL::SaveCurrentGame(USlotBasedSaveGame* SaveGameObject, const FString& ToSlot)
{
	SaveGameObject->SavedSlotInfo.SlotName = ToSlot;
	SaveGameObject->SavedSlotInfo.DateTime = FDateTime::Now();
	FRotator Temp = SaveGameObject->SavedPlayerInfo.ControlRotation;
	// DEBUG_MESSAGE("P:%f  Y:%f  R:%f", Temp.Pitch, Temp.Yaw, Temp.Roll);
	// DEBUG_MESSAGE("X:%f Y:%f Z:%f", Temp.X, Temp.Y, Temp.Z);
	if (UGameplayStatics::SaveGameToSlot(SaveGameObject, ToSlot, 0)) {
		// DEBUG_MESSAGE("GameSaveSuccess");
	}
	else {
		// DEBUG_MESSAGE("GameSaveFail");
	}
	
}

USlotBasedSaveGame* UGameKitFL::LoadSpecificSlot(const FString& SlotName)
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		GameInstanceInterfacePtr->SetCurrentSlot(SlotName);
		USlotBasedSaveGame* SlotBasedSaveGame = Cast<USlotBasedSaveGame>(UGameplayStatics::LoadGameFromSlot(SlotName, 0));
		FRotator Temp = SlotBasedSaveGame->SavedPlayerInfo.ControlRotation;
		// DEBUG_MESSAGE("P:%f  Y:%f  R:%f", Temp.Pitch, Temp.Yaw, Temp.Roll);
		/*FVector Temp = SlotBasedSaveGame->SavedPlayerInfo.PlayerTransform.GetLocation();
		DEBUG_MESSAGE("X:%f Y:%f Z:%f", Temp.X, Temp.Y, Temp.Z);*/
		if (SlotBasedSaveGame->IsValidLowLevel())
			return SlotBasedSaveGame;
		else return nullptr;
	}
	else return nullptr;
}

FString UGameKitFL::GetCurrentlyPlayingSlot()
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		return GameInstanceInterfacePtr->GetCurrentSlot();
	}
	else return FString();
}

FSavedPlayerInfo UGameKitFL::GetPlayerSaveData()
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		return GameInstanceInterfacePtr->GetPlayerSaveDataReference();
	}
	else return FSavedPlayerInfo();
}

void UGameKitFL::UpdatePlayerSaveData(const FSavedPlayerInfo& PlayerInfo)
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		GameInstanceInterfacePtr->UpdatePlayerSaveDataReference(PlayerInfo);
		return;
	}
	else return;
}

void UGameKitFL::UpdateGameplaySaveData(const FSavedGameplayInfo& PlayerInfo)
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		GameInstanceInterfacePtr->SetGameplaySaveDataReference(PlayerInfo);
		return;
	}
	else return;
}

FSavedGameplayInfo UGameKitFL::GetGameplaySaveData()
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		return GameInstanceInterfacePtr->GetGameplaySaveDataReference();

	}
	else return FSavedGameplayInfo();
}

void UGameKitFL::CreateNewGame(USlotBasedSaveGame*& OutSaveGameObject, FString& OutCreatedSlot)
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		for (int LocCheckedSlot = 0; LocCheckedSlot < MaxSlotNumbers; ++LocCheckedSlot) {
			FString SlotName = GameInstanceInterfacePtr->GetDefaultSlotName();
			if (UGameplayStatics::DoesSaveGameExist((SlotName + FString::FromInt(LocCheckedSlot)), 0)) {
				continue;
			}
			else {
				OutSaveGameObject = Cast<USlotBasedSaveGame>(UGameplayStatics::CreateSaveGameObject(USlotBasedSaveGame::StaticClass()));
				OutCreatedSlot = (SlotName + FString::FromInt(LocCheckedSlot));
				if (!OutSaveGameObject->IsValidLowLevel()) return;
				UGameplayStatics::SaveGameToSlot(OutSaveGameObject, OutCreatedSlot, 0);
				GameInstanceInterfacePtr->SetCurrentSlot(OutCreatedSlot);
				break;
			}
		}
	}
	else return;
}

TArray<FString> UGameKitFL::FindSavedGames()
{
	TArray<FString> LocSavedGames;
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		FString SlotName = GameInstanceInterfacePtr->GetDefaultSlotName();
		for (int32 LocCheckedSlot = 0; LocCheckedSlot < MaxSlotNumbers; ++LocCheckedSlot) {
			if (UGameplayStatics::DoesSaveGameExist((SlotName + FString::FromInt(LocCheckedSlot)), 0)) {
				LocSavedGames.Add((SlotName + FString::FromInt(LocCheckedSlot)));
			}
			else {
				for (int32 j = 0; j < LocSavedGames.Num(); ++j) {
					for (int32 k = 0; k < LocSavedGames.Num() - 1; ++k) {			
						FDateTime HD = LoadSpecificSlot(LocSavedGames[k])->SavedSlotInfo.DateTime;
						FDateTime LD = LoadSpecificSlot(LocSavedGames[k + 1])->SavedSlotInfo.DateTime;
						if (HD <= LD) {
							FString SweepString = LocSavedGames[k];
							LocSavedGames[k] = LocSavedGames[k + 1];
							LocSavedGames[k + 1] = SweepString;
						}
					}
				}
				return LocSavedGames;
			}
		}
	}
	return LocSavedGames;
}

void UGameKitFL::SwitchInteractionType(const EInteractionType& InteractionType)
{
	GetInterfacePtr(IPlayerControllerInterface, PlayerControllerInterfacePtr, UGameplayStatics::GetPlayerController(GWorld, 0));
	if (PlayerControllerInterfacePtr) {
		PlayerControllerInterfacePtr->UpdateAvailableInteractionType(InteractionType);
		return;
	}
	else return;
}

EInteractionType UGameKitFL::AvailableInteractionType()
{
	GetInterfacePtr(IPlayerControllerInterface, PlayerControllerInterfacePtr, UGameplayStatics::GetPlayerController(GWorld, 0));
	if (PlayerControllerInterfacePtr) {
		return PlayerControllerInterfacePtr->GetAvailableInteractionType();
	}
	else return EInteractionType::Select;
}

void UGameKitFL::RequestInteraction()
{
	if (AvailableInteractionType() == EInteractionType::InteractWithNPC) {
		UMissionSystemFL::GetMissionComponent()->Interaction_With_NPC();
	}
}

void UGameKitFL::UpdateMissionComponentSaveData(FSavedMissionComponent MissionComponent)
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		GameInstanceInterfacePtr->UpdateMissionCSaveReference(MissionComponent);
		return;
	}
	else return;
}

FSavedMissionComponent UGameKitFL::GetMissionComponentSaveData()
{
	GetInterfacePtr(IGameInstanceInterface, GameInstanceInterfacePtr, UGameplayStatics::GetGameInstance(GWorld));
	if (GameInstanceInterfacePtr) {
		return GameInstanceInterfacePtr->GetMissionCSaveReference();
	}
	else return FSavedMissionComponent();
}

bool UGameKitFL::InGameMenuOpened()
{
	return GetCurrentGameState() == EGameState::InGameMenu;
}

